/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *	  http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.milib.actionControll {
	import com.googlecode.milib.base.IMLBroadcasterListener;
	import com.googlecode.milib.base.MLActionClass;
	import com.googlecode.milib.vo.MLEventInfo;

	/**
	 * For info see:
	 * [en] http://milib.info/pl/index.php?view=article&catid=35%3Aklasy&id=58%3Amlactioninimidend&option=com_content&Itemid=63
	 * [pl] http://milib.info/index.php?view=article&catid=2%3Aclasses&id=14%3Aclass-mlactioninimidend&option=com_content&Itemid=11
	 * 
	 * @author Marek Brun
	 */
	public class MLActionIniMidEnd extends MLActionClass implements IMLBroadcasterListener {

		public var event_IniStart:String='IniStart';
		public var event_IniFinish:String='IniFinish';
		
		public var event_MidEnter:String='MidEnter';
		public var event_AllMidEnter:String='AllMidEnter';
		public var event_MidOut:String='MidOut';
		
		public var event_EndStart:String='EndStart';
		public var event_EndFinish:String='EndFinish';
		
		private var ini : MLActionClass;
		private var end : MLActionClass;
		private var parent : MLActionIniMidEnd;
		private var isInMid : Boolean;
		private var targetSub : MLActionIniMidEnd;
		private var currentSub : MLActionIniMidEnd;
		
		public function MLActionIniMidEnd(ini:MLActionClass=null, end:MLActionClass=null, parent:MLActionIniMidEnd=null) {
			this.ini=ini ? ini : new EmptyAction();
			this.ini.addListener(this);
			this.end=end ? end : new EmptyAction();
			this.end.addListener(this);
			if(parent){
				this.parent=parent;
				this.parent.addListener(this);
			}
			isInMid=false;
			
		}
		/*abstract*/ protected function doIniFinish():void {}		/*abstract*/ protected function doEnterMid():void {}		/*abstract*/ protected function doAllEnterMid():void {}
		/*abstract*/ protected function doOutMid():void {}
		
		private function enterMid():void {
			doEnterMid();
			broadcastEvent(event_MidEnter);
			if(targetSub){
				startTargetSub();
			}else{
				allEnterMid();
			}
		}
		
		private function allEnterMid():void {
			doAllEnterMid();
			broadcastEvent(event_AllMidEnter);
		}
		
		private function outMid():void {
			doOutMid();
			broadcastEvent(event_MidOut);
			end.start();
		}
		
		override protected function doStart():Boolean {
			if(parent){
				if(parent.currentSub==this){
					ini.start();
					return true;
				}else{
					parent.startSub(this);
					return false;
				}
			}else{
				ini.start();
				return true;
			}
		}
		
		private function startSub(sub:MLActionIniMidEnd):void {
			targetSub=sub;
			isRunningFlag=true;
			if(getIsInMid()){
				if(currentSub && currentSub.getIsRunning()){
					currentSub.finish();
				}else{
					startTargetSub();
				}
			}else{
				start();
			}
		}
		
		private function startTargetSub():void {
			if(currentSub){
				currentSub.removeListener(this);
			}
			currentSub=targetSub;
			targetSub=null;
			currentSub.addListener(this);
			currentSub.start();
		}
		
		override protected function doFinish():Boolean {
			targetSub=null;
			if(getIsInMid()){
				if(currentSub && currentSub.getIsRunning()){
					currentSub.finish();
				}else{
					outMid();
				}
				return false;
			}else{
				if(ini.getIsRunning()){
					ini.finish();
					return false;
				}else if(end.getIsRunning()){
					end.finish();
					return false;
				}else{
					return true;
				}
			}
		}
		
		public function getIsInMid():Boolean {
			return isInMid;
		}
		
		public function getIni():MLActionClass { return ini; }
		public function getEnd():MLActionClass { return end; }
		
		public function enable():void {
			if(getIsRunning()){
				if(currentSub.getIsRunning()){
					currentSub.finish();
				}
			}else{
				start();
			}
		}
		
		public function getIMEParent():MLActionIniMidEnd {
			return parent;
		}
		
		public function setupIMEParent(parent:MLActionIniMidEnd):void {
			if(this.parent==parent){ return; }			if(this.parent){
				this.parent.removeListener(this);
			}
			this.parent=parent;
			this.parent.addListener(this);
		}
		
		override public function dispose():void {
			super.dispose();
			parent=null;			ini=null;			end=null;
			targetSub=null;			currentSub=null;
		}
		
//****************************************************************************
// EVENTS for MIIniSubsEnd
//****************************************************************************
		public function onEvent(ev:MLEventInfo):void {
			switch(ev.hero){
				case ini:
					switch(ev.event){
						case ini.event_ActionStart:
							broadcastEvent(event_IniStart);
						break;
						case ini.event_ActionFinish:
							isInMid=true;
							broadcastEvent(event_IniFinish);
							doIniFinish();
							if(getIsRunningFlag()){
								enterMid();
							}else{
								outMid();
							}
						break;
					}
				break;
				case end:
					switch(ev.event){
						case end.event_ActionStart:
							isInMid=false;
							broadcastEvent(event_EndStart);
						break;
						case end.event_ActionFinish:
							broadcastEvent(event_EndFinish);
							if(isRunningFlag){
								ini.start();
							}else{
								finish();
							}
						break;
					}
				break;
				case currentSub:
					switch(ev.event){
						case currentSub.event_ActionFinish:
							currentSub=null;
							if(getIsRunningFlag()){
								enterMid();
							}else{
								finish();
							}
						break;
					}
				break;
				case parent:
					switch(ev.event) {
						case parent.event_AllMidEnter:
							allEnterMid();
							break;
					}
				break;
			}
		}
		
		
	}
}
